package cn.school.student.service.impl;

import cn.school.common.api.CommonResult;
import cn.school.common.utils.SysUserUtils;
import cn.school.common.utils.poi.ExcelPoi;
import cn.school.educational.entity.Subject;
import cn.school.educational.service.SubjectService;
import cn.school.student.dao.ExamListDao;
import cn.school.student.entity.StudentInfo;
import cn.school.student.service.ExamListService;
import cn.school.student.service.ExamResultInfoService;
import cn.school.student.service.ExamResultService;
import cn.school.student.service.StudentInfoService;
import cn.school.student.vo.*;
import cn.school.sys.entity.SysUser;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.poi.ss.usermodel.*;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ExamListServiceImpl extends ServiceImpl<ExamListDao, ExamListVO> implements ExamListService, IService<ExamListVO> {

    @Resource
    private ExamListDao examListDao;

    @Resource
    private ExamResultService examResultService;

    @Resource
    private StudentInfoService studentInfoService;

    @Resource
    private SubjectService subjectService;

    @Resource
    private ExamResultInfoService examResultInfoService;

    @Override
    public IPage<ExamListVO> findExamInfoPageList(ExamListVO vo) {
        int count =  examListDao.findExamListPageListCount(vo);
        int startNum=(vo.getPageNum()-1)*vo.getPageSize();
        vo.setPageNum(startNum);
        List<ExamListVO> examInfoList =  examListDao.findExamListPageList(vo);
        IPage<ExamListVO> page = new Page<>();
        page.setTotal(count);
        page.setRecords(examInfoList);
        return page;
    }

    @Transactional
    @Override
    public int deleteExamListById(String id) {
        if(examListDao.deleteById(id) > 0){
            return examResultService.deleteByExamId(id);
        }
        return -1;
    }

    @Override
    public int addOrUpdateExamList(ExamListVO vo) {
        String userName = SysUserUtils.getSysUser().getUsername();
        int num = 0;
        if(StringUtils.isEmpty(vo.getId())){
            vo.setCreateBy(userName);
            vo.setCreateTime(new Date());
            num = examListDao.insert(vo);
        }else{
            vo.setModifyBy(userName);
            vo.setModifyTime(new Date());
            num = examListDao.updateById(vo);
        }
        return num;
    }

    @Transactional
    @Override
    public boolean addExamResult(ResultTableVO vo) {
        String username = SysUserUtils.getSysUser().getUsername();
        //新增 考试表
        ExamListVO examListVO = new ExamListVO();
        examListVO.setTermId(vo.getTermId().toString());
        examListVO.setClassId(vo.getClassId().toString());
        examListVO.setExamName(vo.getExamName());
        examListVO.setDescription(vo.getDescription());
        examListVO.setCreateBy(username);
        String subjectName = vo.getStudentWithSubjectVOList().get(0).getSubjList()
                .stream()
                .map(SubjectVO::getSubjName)
                .collect(Collectors.joining(","));
        examListVO.setSubjectName(subjectName);
        this.baseMapper.insert(examListVO);
        //考试 ID
        Long examId = examListVO.getId();
        //学生 集合
        List<StudentWithSubjectVO> studentWithSubjectVOList = vo.getStudentWithSubjectVOList();

        //考试成绩 集合
        List<ResultVO> resultVOList = new ArrayList<>();
        //科目集合
        List<SubjectVO> subjectVOList = new ArrayList<>();
        for (StudentWithSubjectVO studentWithSubjectVO : studentWithSubjectVOList) {
                subjectVOList = studentWithSubjectVO.getSubjList();
            for (SubjectVO subjectVO : subjectVOList) {
                //考试成绩 对象
                ResultVO resultVO = new ResultVO();
                resultVO.setStudentId(studentWithSubjectVO.getId());
                resultVO.setStudentName(studentWithSubjectVO.getName());
                resultVO.setExamId(Integer.parseInt(examId.toString()));
                resultVO.setStatus(1);
                resultVO.setCreateBy(username);
                resultVO.setSubjectId(subjectVO.getId());
                resultVO.setScore(subjectVO.getScore());
                resultVOList.add(resultVO);
            }
        }
        //批量新增
        examResultService.batchAddResult(resultVOList);
        return true;
    }

    @Transactional
    @Override
    public boolean updateExamResult(ResultTableVO vo) {
        String username = SysUserUtils.getSysUser().getUsername();
        //学生 集合
        List<StudentWithSubjectVO> studentWithSubjectVOList = vo.getStudentWithSubjectVOList();
        //考试成绩 集合
        List<ResultVO> resultVOList = new ArrayList<>();
        //科目集合
        List<SubjectVO> subjectVOList = new ArrayList<>();
        for (StudentWithSubjectVO studentWithSubjectVO : studentWithSubjectVOList) {
            subjectVOList = studentWithSubjectVO.getSubjList();
            for (SubjectVO subjectVO : subjectVOList) {
                //考试成绩 对象
                ResultVO resultVO = new ResultVO();
                resultVO.setId(subjectVO.getResultId());
                resultVO.setExamId(Integer.parseInt(vo.getId().toString()));
                resultVO.setStudentId(studentWithSubjectVO.getId());
                resultVO.setStudentName(studentWithSubjectVO.getName());
                resultVO.setStatus(1);
                resultVO.setModifyBy(username);
                resultVO.setSubjectId(subjectVO.getId());
                resultVO.setScore(subjectVO.getScore());
                resultVOList.add(resultVO);
            }
        }
        //批量修改
        examResultService.batchUpdateResult(resultVOList);
        return true;
    }

    @Override
    public ResultTableVO searchResult(String examId) {
        //考试对象
        ExamListVO examListVO = this.baseMapper.selectById(examId);
        //表中查询到的学生成绩
        List<ResultVO> resultVOList = examResultService.selectResultByExamId(examId);
        //要返回给前端的数据
        ResultTableVO resultTableVO = new ResultTableVO();
        resultTableVO.setId(examListVO.getId());
        resultTableVO.setExamName(examListVO.getExamName());
        //学生HashSet，保证学生 ID 唯一性
        Set<Integer> studentSet = new HashSet();
        Map<Integer,StudentWithSubjectVO> studentMap = new HashMap<>();
        //学生 ID
        int studentId = 0;
        List<StudentWithSubjectVO> studentWithSubjectVOList = new ArrayList<>();
        //当前学生
        StudentWithSubjectVO studentWithSubjectVO = new StudentWithSubjectVO();
        List<SubjectVO> subjList = new ArrayList<>();
        studentWithSubjectVO.setSubjList(subjList);
        for (ResultVO resultVO : resultVOList) {
            studentId = resultVO.getStudentId();
            if(!studentSet.contains(studentId)){
                studentWithSubjectVO = new StudentWithSubjectVO();
                studentWithSubjectVO.setId(studentId);
                studentWithSubjectVO.setName(resultVO.getStudentName());
                subjList = new ArrayList<>();
                studentWithSubjectVO.setSubjList(subjList);
                studentWithSubjectVOList.add(studentWithSubjectVO);
                studentMap.put(studentWithSubjectVO.getId(),studentWithSubjectVO);
            }else{
                studentWithSubjectVO = studentMap.get(studentId);
            }
            //当前学生的各科成绩
            List<SubjectVO> subjList2 = studentWithSubjectVO.getSubjList();
            SubjectVO subjectVO = new SubjectVO();
            subjectVO.setResultId(resultVO.getId());
            subjectVO.setId(resultVO.getSubjectId());
            subjectVO.setSubjName(resultVO.getSubjectName());
            //分数
            subjectVO.setScore(resultVO.getScore());
            subjList2.add(subjectVO);
            studentWithSubjectVO.setSubjList(subjList2);
            studentSet.add(studentId);
        }
        resultTableVO.setStudentWithSubjectVOList(studentWithSubjectVOList);
        return resultTableVO;
    }

    @Transactional
    @Override
    public Boolean importExcel(MultipartFile file,ResultTableVO vo) throws Exception {
        Workbook workbook = WorkbookFactory.create(file.getInputStream());
        Sheet sheet = workbook.getSheetAt(0);
        String userName = SysUserUtils.getSysUser().getUsername();
        Set subjects = new HashSet();            //班级已经分配的学科
        Map<String,String> subjMap = new HashMap<>();//班级已经分配的学科 名称 与 id 的映射
        List<SubjectVO> subjList = vo.getStudentWithSubjectVOList().get(0).getSubjList();
        for (int i = 0; i < subjList.size(); i++) {
            subjects.add(subjList.get(i).getSubjName());
            subjMap.put(subjList.get(i).getSubjName(),subjList.get(i).getId().toString());
        }
        Set students = new HashSet();             //班级的所有学生
        Map<String,String> stuMap = new HashMap<>();//班级的所有学生 名称 与 id 的映射
        List<StudentWithSubjectVO> studentWithSubjectVOList = vo.getStudentWithSubjectVOList();
        for (int i = 0; i < studentWithSubjectVOList.size(); i++) {
            students.add(studentWithSubjectVOList.get(i).getStudentId());
            stuMap.put(studentWithSubjectVOList.get(i).getStudentId(),String.valueOf(studentWithSubjectVOList.get(i).getId()));
        }
        //新增 考试表
        ExamListVO examListVO = new ExamListVO();
        examListVO.setTermId(vo.getTermId().toString());
        examListVO.setClassId(vo.getClassId().toString());
        examListVO.setExamName(vo.getExamName());
        examListVO.setDescription(vo.getDescription());
        examListVO.setCreateBy(userName);
        String subjectName = subjList
                .stream()
                .map(SubjectVO::getSubjName)
                .collect(Collectors.joining(","));
        examListVO.setSubjectName(subjectName);
        this.baseMapper.insert(examListVO);
        //考试 ID
        int examId = Integer.parseInt(examListVO.getId().toString());
        //考试成绩 集合
        List<ResultVO> resultVOList = new ArrayList<>();
        for (int c = 2;c < sheet.getRow(1).getLastCellNum();c++){
            int r = 1;
            Row row = sheet.getRow(r++);               //学科行
            Cell cell = row.getCell(c);
            String subjName = (String) ExcelPoi.getCellValue(cell);
            if(!subjects.contains(subjName)){   //excel表中的学科没有与班级绑定
                throw new RuntimeException("导入失败！");
            }
            while (r <= sheet.getLastRowNum()){
                row = sheet.getRow(r++);
                //学生学号列
                cell = row.getCell(0);
                String studentId = (String) ExcelPoi.getCellValue(cell);
                if(!students.contains(studentId)){   //班级没有excel中的某个学生
                    throw new RuntimeException("导入失败！");
                }
                cell = row.getCell(1);
                String studentName = (String) ExcelPoi.getCellValue(cell);
                //成绩列
                cell = row.getCell(c);
                StudentInfo studentInfo = studentInfoService.getStudentInfo(stuMap.get(studentId));
                ResultVO resultVO = new ResultVO();
                resultVO.setExamId(examId);
                resultVO.setStudentId(Integer.parseInt(studentInfo.getId().toString()));
                resultVO.setStudentName(studentName);
                resultVO.setSubjectId(Long.parseLong(subjMap.get(subjName)));
                resultVO.setScore(Double.parseDouble((String) ExcelPoi.getCellValue(cell)));
                resultVO.setStatus(1);
                resultVO.setCreateBy(userName);
                resultVOList.add(resultVO);
            }
        }
        examResultService.batchAddResult(resultVOList);
        return true;
    }

    @Override
    public List<ExamVO> searchResultById(String userId) {
        List<ExamVO> examVOList = examListDao.searchResultById(Long.parseLong(userId));
        return examVOList;
    }
}
